using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration.Health;
using SPHealth.SharePoint.HealthRules.SP.Rules.Availability;
using SPHealth.SharePoint.HealthRules.SP.Rules.Configuration;
using SPHealth.SharePoint.HealthRules.SP.Rules.Performance;
using SPHealth.SharePoint.HealthRules.SP.Rules.Security;
using SPHealth.SharePoint.HealthRules.SP.Rules.Sys;

namespace SPHealth.SharePoint.HealthRules.Features.FarmDeployRules
{
    [Guid("e304635e-ad2b-465e-8ac9-a8fe1f802599")]
    public class FarmDeployRulesEventReceiver : SPFeatureReceiver
    {
        SPList configList;

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            // get our assembly name
            Assembly a = Assembly.Load(this.GetType().Assembly.FullName);

            // register all the rules the assembly contains
            IDictionary<Type, Exception> exceptions = SPHealthAnalyzer.RegisterRules(a);

            // process any errors that occured whilst registering the rules
            #region ProcessErrors
            if (exceptions != null)
            {
                string logEntry = a.FullName;
                if (exceptions.Count == 0)
                {
                    logEntry += " All rules were registered.";
                }
                else
                {
                    foreach (KeyValuePair<Type, Exception> pair in exceptions)
                    {
                        logEntry += string.Format(" Registration failed for type {0}. {1}",
                                                  pair.Key, pair.Value.Message);
                    }
                }
                System.Diagnostics.Trace.WriteLine(logEntry);
            }
            #endregion

            // create a list to store rule configuration
            #region Create Configuration List
            using (SPWeb centralAdminWeb = common.GetCentralAdminWeb())
            {
                if (centralAdminWeb != null)
                {
                    // does the config list already exist?
                    configList = centralAdminWeb.Lists.TryGetList(common.LIST_RuleConfigurations);

                    // if not create it
                    if (configList == null)
                    {
                        centralAdminWeb.Lists.Add(
                            common.LIST_RuleConfigurations,
                            "Stores the configurations used by some of the SPHealth.SharePoint.HealthRules health analyszer rules.",
                            centralAdminWeb.ListTemplates["Custom List"]);

                        // get our newly created list
                        configList = centralAdminWeb.Lists.TryGetList(common.LIST_RuleConfigurations);

                        // configure our list as needed
                        #region Configure Title Column
                        SPField title = configList.Fields["Title"];
                        title.Required = true;
                        title.ShowInEditForm = false;
                        title.EnforceUniqueValues = true;
                        title.Indexed = true;
                        title.Update();
                        #endregion

                        #region Configure Settings Column
                        configList.Fields.Add("Settings", SPFieldType.Note, false);
                        SPFieldMultiLineText settings = new SPFieldMultiLineText(configList.Fields, "Settings");
                        settings.Required = true;
                        settings.RichTextMode = SPRichTextMode.Compatible;
                        settings.Update();
                        #endregion

                        #region Configure Default View
                        SPView defaultView = configList.DefaultView;
                        SPViewFieldCollection vfc = defaultView.ViewFields;
                        vfc.Add(settings);
                        defaultView.Update();
                        #endregion

                        // save our list changes
                        configList.Update();
                    }
                }
            }
            #endregion

            // populate our default rule configurations
            // TODO: Is there a more elegant way of itterating over the rules contained by the current assembly?
            AddConfigListItem(WarnContentDatabaseBackup.GetTitle(), WarnContentDatabaseBackup.GetDefaultSettings());
            AddConfigListItem(WarnContentDatabaseSize.GetTitle(), WarnContentDatabaseSize.GetDefaultSettings());
            AddConfigListItem(WarnAssembliesCompiledInDebug.GetTitle(),WarnAssembliesCompiledInDebug.GetDefaultSettings());
            AddConfigListItem(WarnServiceIsSinglePointOfFailure.GetTitle(), WarnServiceIsSinglePointOfFailure.GetDefaultSettings());
            AddConfigListItem(WarnExcessiveUniquelySecuredItems.GetTitle(), WarnExcessiveUniquelySecuredItems.GetDefaultSettings());
            AddConfigListItem(WarnFarmBackupHistory.GetTitle(), WarnFarmBackupHistory.GetDefaultSettings());
            AddConfigListItem(WarnDatabaseCapacity.GetTitle(), WarnDatabaseCapacity.GetDefaultSettings());
            AddConfigListItem(WarnAutoGrowthSettings.GetTitle(), WarnAutoGrowthSettings.GetDefaultSettings());
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            // get our assembly name
            Assembly a = Assembly.Load(this.GetType().Assembly.FullName);

            // unregister all the rules the assembly contains
            IDictionary<Type, Exception> exceptions = SPHealthAnalyzer.UnregisterRules(a);

            if (exceptions != null)
            {
                string logEntry = a.FullName;
                if (exceptions.Count == 0)
                {
                    logEntry += " All rules were unregistered.";
                }
                else
                {
                    foreach (KeyValuePair<Type, Exception> pair in exceptions)
                    {
                        logEntry += string.Format(" Unregistration failed for type {0}. {1}",
                                                  pair.Key, pair.Value.Message);
                    }
                }
                System.Diagnostics.Trace.WriteLine(logEntry);
            }
        }

        // used to create the default settings for rules in the config list
        private void AddConfigListItem(string title, IDictionary<string, string> settings)
        {
            // add a new item to the configuration list
            try
            {
                // build our xml settings string
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("<Properties>");
                foreach (string key in settings.Keys)
                {
                    if (key.StartsWith("Comment"))
                    {
                        // Add a comment to the configuration
                        sb.AppendLine(string.Format("   <!-- {0} -->", settings[key]));
                    }
                    else
                    {
                        // Add a parameter to the configuration
                        sb.AppendLine(string.Format("   <Property Key=\"{0}\" Value=\"{1}\" />", key, settings[key]));
                    }
                }
                sb.AppendLine("</Properties>");

                // create our settings item
                SPListItem item = configList.Items.Add();
                item["Title"] = title;
                item["Settings"] = sb.ToString();
                item.Update();
            }
            catch { /* TODO */ } // could be a duplicate value
        }

    }
}
